﻿/*-----------------------------------------------
// File: BattleCharacter.cs 
// Description: 渲染层一个英雄实例对象
// Author: Shaobing	492057342@qq.com
-----------------------------------------------*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using AssetLoad;

namespace Battle.View
{
    public class BattleCharacter : Fsm.FsmControllerBaseMono<ActorState>
    {
        public GameObject model;
        public LegacyAnimation anim;
        public BloodBarKit hpBar;
        public BloodBarNumControl Hpbar { set; get; }
        public string uniqueId;       // 唯一ID
        public string heroId;          // HeroId
        public BattleCamp camp;
        public int FPId;
        public string weaponId;

        double _hp;
        public void SetHP(double value)
        {
            _hp = value;
            if (_hp <= 0)
            {
                _hp = 0;
            }
            else if (_hp >= _maxHp)
            {
                _hp = _maxHp;
            }
            RefreshHPUI();
        }
        public void AddHP(double inf, bool showHPBar = true)
        {
            _hp += inf;
            if (showHPBar)
                RefreshHPUI();

        }
        public void SetMaxHP(double value)
        {
            _maxHp = value;
            RefreshHPUI();
        }
        void RefreshHPUI()
        {
            if (hpBar != null && isAlive)
            {
                ShowHpBar(2);
            }
            if (BattleViewCtrl.GetInstance().IsCurrentShowBC(this) && BattleViewCtrl.GetInstance().curRunningCamp == BattleCamp.Attacker)
            {
                BattleManager.Instance.battlePanel.ShowEnemyInfo(this);
            }
        }
        public void ShowHpBar(float time)
        {
            Hpbar = hpBar.GetComponent<BloodBarNumControl>();
            float v = (float)(_hp / _maxHp);
            if (v > 1f)
            {
                v = 1f;
            }
            else if (v < 0f)
            {
                v = 0f;
            }
            Hpbar.SetNowBarValue(v);
            Hpbar.Show(time);
        }
        public double hp
        {
            get {
                if (_hp > _maxHp)
                {
                    return _maxHp;
                }
                else if (_hp < 0)
                {
                    return 0;
                }
                return _hp;
            }
        }
        double _maxHp;
        public double maxHp
        {
            get { return _maxHp; }
        }

        public string heroName;
        public string resourceName;
        public string iconName;

        public float width;
        public float height;
        public float length;
        /// <summary>
        /// 模型缩放
        /// </summary>
        public float modelScale;
        public float particleScale;

        public int heroClass;
        public string beFoundBone;
        public double rushFlyTime;
        public double rushFallTime;
        public double jumpBackFlyTime;
        public double jumpBackFallTime;

        public BuffTransform0 buffTransform0;

        BattleSkill firstSkill;
        BattleSkill secondSkill;
        UltimateSkill ultimateSkill;
        // 逻辑判断技能是否释放过，以实时情况为准
        public bool IsSkillCanCast(SkillType t)
        {
            var skill = GetSkill(t);
            if (skill != null)
            {
                return skill.IsSkillCanCast() && isAlive;
            }
            return false;
        }
        // 以行为上判断技能是否被释放过，以玩家操作/消息指令为准
        public bool IsSkillCanCast4UI(SkillType t)
        {
            var skill = GetSkill(t);
            if (skill != null)
            {
                return skill.IsSkillCanCast4UI() && isAlive;
            }
            return false;
        }

        List<BattleBuffer> ownBuffs = new List<BattleBuffer>();
        //List<BattleBuff> ownBuffs = new List<BattleBuff>();
        public void AddBuff(BattleBuffer buff)
        {
            ownBuffs.Add(buff);
            if (!string.IsNullOrEmpty(buff.iconName))
            {
                buffTransform0.AddBuffIcon(buff.iconName);
            }
            if (buff.isStun)
            {
                stunNumber++;
            }
            //buffTransform.AddBuffIcon(buff.iconName);
        }
        public void RemoveBuff(BattleBuffer buff)
        {
            ownBuffs.Remove(buff);
            if (!string.IsNullOrEmpty(buff.iconName))
            {
                buffTransform0.RemoveBuffIcon(buff.iconName);
            }
            if (buff.isStun)
            {
                stunNumber--;
            }
            //buffTransform.RemoveBuffIcon(buff.iconName);
        }
        public void ClearBuff()
        {
            List<string> bufUids = new List<string>();
            foreach (var buf in ownBuffs)
            {
                bufUids.Add(buf.uniqueId);
            }
            foreach (var uid in bufUids)
            {
                BattleViewCtrl.GetInstance().RemoveBattleBuff(uid);
            }
        }

        public bool isAlive;

        private int stunNumber = 0;
        public bool IsStun
        {
            get
            {
                return stunNumber > 0;
            }
        }
        public bool isHealer = false;

        public ParticleData deadParticleData
        {
            get
            {
                return BattleFactory.GetDeadParticleData();
            }
        }
        public ParticleData rushParticleData
        {
            get
            {
                return BattleFactory.GetRushParticleData();
            }
        }
        public ParticleData ultiSingParticleData
        {
            get
            {
                return BattleFactory.GetSingParticleData();
            }
        }

        #region Init

        public void Init(BattleActorData data, BattleCamp camp)
        {
            InitState();
            InitBC(data, camp);
            InitSkill(data);
            InitBuff(data);
        }


        void InitBC(BattleActorData data, BattleCamp camp)
        {
            this.camp = camp;
            SetData(data);
            if (data.hp <= 0)
            {
                isAlive = false;
                SwitchState(ActorState.Dead);
            }
            else
            {
                isAlive = true;
            }
        }


        void InitSkill(BattleActorData data)
        {
            firstSkill = null;
            secondSkill = null;
            ultimateSkill = null;
            foreach (var skill in data.skills)
            {
                if (skill.skillIndex == (int)SkillType.Skill1)
                {
                    firstSkill = new BattleSkill(skill, this);
                }
                else if (skill.skillIndex == (int)SkillType.Skill2)
                {
                    secondSkill = new BattleSkill(skill, this);
                }
                else if (skill.skillIndex == (int)SkillType.Ultimate)
                {
                    ultimateSkill = new UltimateSkill(skill, this);
                }
            }
        }
        void InitBuff(BattleActorData data)
        {
            // TODO
        }
        #endregion

        #region Refresh
        public void Refresh(BattleActorData data)
        {
            RefreshBC(data);
            RefreshSkill(data);
            RefreshBuff(data);
        }

        void RefreshBC(BattleActorData data)
        {
            SetData(data);
            if (hp <= 0 && isAlive)
            {
                SwitchState(ActorState.Dead);
            }
        }

        void RefreshSkill(BattleActorData data)
        {
            foreach (var _skill in data.skills)
            {
                var skill = GetSkill((SkillType)_skill.skillIndex);
                if (skill != null)
                {
                    skill.Refresh(_skill);
                }
            }
        }

        public void Refresh(ProtoBuf.Message.Actor actor)
        {
            RefreshBC(actor);
            RefreshSkill(actor);
            RefreshBuff(actor);
        }
        void RefreshBC(ProtoBuf.Message.Actor actor)
        {
#if UNITY_EDITOR
            if (actor.hp != hp)
            {
                Debug.LogError("[RefreshBC] Name:" + name + " View Hp:" + hp + " Engine Hp:" + actor.hp);
            }
#endif
            SetData(actor);
            if (hp <= 0 && isAlive)
            {
                SwitchState(ActorState.Dead);
            }
        }

        void RefreshSkill(ProtoBuf.Message.Actor actor)
        {
            foreach (var _skill in actor.skills)
            {
                var skill = GetSkill((SkillType)_skill.skillType);
                if (skill != null)
                {
                    skill.Refresh(_skill);
                }
            }
        }
        void RefreshBuff(ProtoBuf.Message.Actor actor)
        {
            List<BattleBuffer> lastBuffs = new List<BattleBuffer>();
            List<ProtoBuf.Message.Buffer> newBuffs = new List<ProtoBuf.Message.Buffer>();
            foreach (var bufData in actor.buffers)
            {
                bool isNewBuff = true;
                foreach (var buf in ownBuffs)
                {
                    if (buf.uniqueId == bufData.uid)
                    {
                        lastBuffs.Add(buf);
                        isNewBuff = false;
                        break;
                    }
                }
                if (isNewBuff)
                    newBuffs.Add(bufData);
            }
            List<BattleBuffer> needRemoveBuffs = new List<BattleBuffer>();
            foreach (var buf in ownBuffs)
            {
                if (lastBuffs.Contains(buf))
                {
                    continue;
                }
                needRemoveBuffs.Add(buf);
            }
            foreach (var buf in needRemoveBuffs)
            {
                BattleViewCtrl.GetInstance().RemoveBattleBuff(buf.uniqueId);
            }
            foreach (var buffData in newBuffs)
            {
                BattleViewCtrl.GetInstance().AddBattleBuff(buffData);
            }
        }

        void RefreshBuff(BattleActorData data)
        {
            foreach (var buf in ownBuffs)
            {
                BattleViewCtrl.GetInstance().RemoveBattleBuff(buf.uniqueId);
            }
        }
        #endregion

        void SetData(ProtoBuf.Message.Actor actor)
        {
            uniqueId = actor.uid;
            heroId = actor.heroId;
            _hp = actor.hp;
            _maxHp = actor.maxhp;
            FPId = actor.FPId;
            var dh = Dict.Blo.DictHeroBlo.GetTableHero(heroId);
            if (dh.heroClass != (int)HeroClass.Main_Actor_Man && dh.heroClass != (int)HeroClass.Main_Actor_Woman)
            {
                heroName = TableTextBlo.GetText(dh.name);
            }
            else
            {
                var defender = StaticData.curBattleData.defendFighters[0];
                var attacker = StaticData.curBattleData.attackFighters[0];
                heroName = camp == BattleCamp.Defender ? defender.role.nickName : attacker.role.nickName;
            }
            resourceName = dh.resName;
            iconName = dh.iconName;
            width = (float)dh.Weight;
            height = (float)dh.Height;
            length = (float)dh.Length;
            beFoundBone = dh.BeFoundBone;
            rushFlyTime = dh.RushFlyTime;
            rushFallTime = dh.RushFallTime;
            jumpBackFlyTime = dh.JumpBackFlyTime;
            jumpBackFallTime = dh.JumpBackFallTime;
            heroClass = dh.heroClass;
            this.weaponId = actor.weaponId;
            modelScale = (float)dh.ScaleFactor;
            particleScale = GetParticleScale();
        }
        void SetData(BattleActorData data)
        {
            uniqueId = data.uniqueId;
            heroId = data.heroId;
            _hp = data.hp;
            _maxHp = data.maxHp;
            FPId = data.fpid;
            var dh = Dict.Blo.DictHeroBlo.GetTableHero(heroId);
            heroName = TableTextBlo.GetText(dh.name);
            resourceName = dh.resName;
            iconName = dh.iconName;
            width = (float)dh.Weight;
            height = (float)dh.Height;
            length = (float)dh.Length;
            beFoundBone = dh.BeFoundBone;
            rushFlyTime = dh.RushFlyTime;
            rushFallTime = dh.RushFallTime;
            jumpBackFlyTime = dh.JumpBackFlyTime;
            jumpBackFallTime = dh.JumpBackFallTime;
            heroClass = dh.heroClass;
            this.weaponId = data.weaponId;
            modelScale = (float)dh.ScaleFactor;
            particleScale = GetParticleScale();
        }

        float GetParticleScale()
        {
            var scaleDep = Dict.Blo.DictConfigBlo.GetParticleScaleDependence();
            var arr = scaleDep.Split(new char[1] { ',' }, System.StringSplitOptions.RemoveEmptyEntries);
            float h = float.Parse(arr[0]);
            //float w = float.Parse(arr[1]);
            //float l = float.Parse(arr[2]);
            float scaleH = height / h;
            float scaleW = width / h;
            float scaleL = length / h;
            return (scaleH >= scaleW ? scaleH : scaleW) >= scaleL ? (scaleH >= scaleW ? scaleH : scaleW) : scaleL;
        }
        //public Vector3 GetBeFoundBonePosition()
        //{
        //    return GetBonePosition(beFoundBone);
        //}
        Transform befondTransform = null;
        public Vector3 GetBeFoundBonePosition()
        {
            //在BattleCamera的update里频繁调用，所以缓存起来
            if (befondTransform == null)
            {
                befondTransform = GetBindTransform(beFoundBone);
                if (befondTransform == null)
                {
                    befondTransform = transform;
                }
            }
            return befondTransform.position;
        }
        public Vector3 GetBonePosition(string boneName)
        {
            Transform trans = GetBindTransform(boneName);
            if (trans != null)
                return trans.position;
            else
                return new Vector3(0, height / 2f, 0f);
        }


        public BattleSkill GetSkill(SkillType skillType)
        {
            switch (skillType)
            {
                case SkillType.Skill1: return firstSkill;
                case SkillType.Skill2: return secondSkill;
                case SkillType.Ultimate: return ultimateSkill;
            }
            return null;
        }


        public override void InitState()
        {
            allStates = new Dictionary<ActorState, Fsm.FsmStateMonoBase<ActorState>>();
            allStates[ActorState.None] = new BCNoneState(ActorState.None, this);
            allStates[ActorState.Entrance] = new BCEntranceState(ActorState.Entrance, this);
            allStates[ActorState.TransFormation] = new BCTransFormationState(ActorState.TransFormation, this);
            allStates[ActorState.AttackReady] = new BCAttackReadyState(ActorState.AttackReady, this);
            allStates[ActorState.Attack] = new BCAttackState(ActorState.Attack, this);
            allStates[ActorState.AttackMoveBackward] = new BCAttackMoveBackState(ActorState.AttackMoveBackward, this);
            allStates[ActorState.AttackMoveForward] = new BCAttackMoveForwardState(ActorState.AttackMoveForward, this);
            allStates[ActorState.AttackWait] = new BCAttackWaitState(ActorState.AttackWait, this);
            allStates[ActorState.Defend] = new BCDefendState(ActorState.Defend, this);
            allStates[ActorState.Dead] = new BCDeadState(ActorState.Dead, this);
            allStates[ActorState.Ultimate] = new BCUltimateState(ActorState.Ultimate, this);
            allStates[ActorState.Ultimated] = new BCBeUltimatedState(ActorState.Ultimated, this);
            allStates[ActorState.Celebrate] = new BCCelebrateState(ActorState.Celebrate, this);
        }

        #region Position
        public Vector3 GetStandPosition()
        {
            return BattleManager.Instance.battleViewCtrl.GetPosition(FPId, camp);
        }

        public Vector3 GetStandEulerAngle()
        {
            if (camp == BattleCamp.Attacker)
                return Vector3.zero;
            else
                return new Vector3(0, 180f, 0f);
        }
        public Vector3 GetEntranceStandPosition()
        {
            if (camp == BattleCamp.Attacker)
                return GetStandPosition() + new Vector3(0, 0, -8f);
            else
                return GetStandPosition();
        }
        public Vector3 GetEntranceStandEulerAngle()
        {
            return GetStandEulerAngle();
        }

        public Vector3 GetAttackReleaseAccodingToPosition()
        {
            if (GetCurrrentStateType() == ActorState.AttackMoveForward)
            {
                var state = GetCurrentState() as BCAttackMoveForwardState;
                return state.GetTargetPos();
            }
            else if (GetCurrrentStateType() == ActorState.AttackMoveBackward)
            {
                return GetStandPosition();
            }
            else
            {
                return transform.localPosition;
            }
        }
        #endregion

        #region Animation

        public bool IsPlayStand()
        {
            return anim.IsPlaying(AniName.IDLE_FIGHT) || anim.IsPlaying(AniName.STAND_WEAK) || anim.IsPlaying(AniName.STUN);
        }

        public float GetAniLength(string aniName)
        {
            return anim.GetAniLength(aniName);
        }
        public void PlayStand(bool isDirectly = false)
        {
            if (IsStun)
            {
                if (anim.anim.GetClip(AniName.STUN) != null)
                {
                    anim.CrossFade(AniName.STUN, WrapMode.Loop);
                }
                else
                {
                    anim.Play(AniName.IDLE_FIGHT, WrapMode.Loop);
                }
            }
            else
            {
                if (isDirectly)
                {
                    anim.Play(AniName.IDLE_FIGHT, WrapMode.Loop);
                }
                else
                {
                    anim.CrossFade(AniName.IDLE_FIGHT, WrapMode.Loop);
                }
            }
        }

        public void PlayUltimateReady()
        {
            //if (anim.anim.GetClip(AniName.ULITMATE_READY) != null && false)
            //{
            //    anim.Play(AniName.ULITMATE_READY, WrapMode.Once);
            //}
            //else
            //{
            //    anim.Play(AniName.IDLE_FIGHT, WrapMode.Loop);
            //}

            anim.Play(AniName.IDLE_FIGHT, WrapMode.Loop);
            if (ultimateSkill != null && !string.IsNullOrEmpty(ultimateSkill.ultimateReadyAudio))
            {
                AudioManager.Instance.PlaySingle(ultimateSkill.ultimateReadyAudio);
            }
        }

        public void PlayRun()
        {
            anim.Play(AniName.RUN_FIGHT, WrapMode.Loop);
        }
        public void PlaySkillAnimation(SkillType skillType)
        {
            var skill = GetSkill(skillType);
            if (skill != null)
            {
                skill.PlaySkillAnimation();
                skill.PlaySkillAudio();
            }
        }

        public void PlayHit(float speed = 1f)
        {
            anim.Play(AniName.BEHIT, WrapMode.Clamp, true, speed);
        }
        public void CrossFadeHit()
        {
            anim.CrossFade(AniName.BEHIT, WrapMode.Clamp, true);
        }

        public void PlayBehitAudio(string hitAudio)
        {
            if (!string.IsNullOrEmpty(hitAudio))
            {
                AudioManager.Instance.Play(hitAudio);
            }
        }

        public void PlayCelebrate()
        {
            anim.Play(AniName.WIN, WrapMode.Loop);
        }

        void CreateBloodBar()
        {
            var hpBarObj = BattleFactory.SpawnBloodBar();
            hpBarObj.transform.SetParent(transform);
            if (camp == BattleCamp.Attacker)
            {
                hpBarObj.transform.localPosition = new Vector3(-width * 0.25f, height * 0.8f, length * 0.25f);
                hpBarObj.transform.localEulerAngles = new Vector3(-90f, -160f, 0f);
            }
            else
            {
                hpBarObj.transform.localEulerAngles = new Vector3(-90f, -30f, 0f);
                hpBarObj.transform.localPosition = new Vector3(width * 0.25f, height * 0.8f, length * 0.25f);
            }
            hpBar = hpBarObj.GetComponent<BloodBarKit>();

            BloodBarNumControl script = hpBarObj.gameObject.GetComponent<BloodBarNumControl>();
            List<BattleFighterData> defendFighters = BattleManager.Instance.battleData.defendFighters;
            script.barNum = 1;
            foreach (var actor in defendFighters)
            {
                foreach (var mon in actor.actors)
                {
                    if (uniqueId == mon.uniqueId)
                    {
                        script.barNum = Mathf.Clamp(mon.bloodNum, 1, 5);
                    }
                }
            }
            script.Init();
            hpBarObj.SetActive(false);
        }

        public void PlayRush()
        {
            anim.Play(AniName.RUSH, WrapMode.Clamp);
        }

        public void PlayJumpForward()
        {
            anim.Play(AniName.JUMP_FORWARD, WrapMode.Clamp);
        }
        public void PlayJumpBackward()
        {
            anim.Play(AniName.JUMP_BACKWARD, WrapMode.Clamp);
        }
        #endregion
        #region Resource
        bool isLoadComplete = false;
        private bool loadedModel = false;
        private bool loadedExtra = false;
        private bool loadedWinAudio = false;
        private bool loadedWeapon = false;
        public bool LoadComplete()
        {
            if(!IsSkillLoadComplete())
            {
                return false;
            }
            bool result = isLoadComplete || (loadedModel && loadedExtra && loadedWinAudio && loadedWeapon);
            if(result)
            {
                if(!isLoadComplete)
                {
                    isLoadComplete = true;
                    Debug.Log("[ResourceLoad] Load BattleCharacter " + name + " cost time: " + (System.DateTime.Now - loadBeginTime).TotalMilliseconds);
                }
            }
            return result;
        }
        private System.DateTime loadBeginTime;
        public void LoadResourceAsync()
        {
            if (isLoadComplete)
                return;
            //StartCoroutine(_LoadResourceAsync());
            var th = Dict.DictDataManager.Instance.tableHeroDao.GetById(heroId);
            var scale = (float)th.ScaleFactor;
            loadBeginTime = System.DateTime.Now;
            gameObject.name = "[" + uniqueId + "]" + heroName;
            StartCoroutine(
                ResourceLoader.GetInstance().modelLoader.LoadModel(resourceName,
                    (asset) =>
                    {
                        model = asset as GameObject;
                        model.transform.SetParent(transform);
                        model.transform.localPosition = Vector3.zero;
                        //model.transform.localScale = Vector3.one;
                        model.transform.localEulerAngles = Vector3.zero;
                        anim = model.GetComponent<LegacyAnimation>();

                        model.GetComponent<ModelRenderKit>().SetModelScale(scale);
                        model.GetComponent<ModelRenderKit>().EnterBattle();
                        loadedModel = true;

                        StartCoroutine(LoadWeapon());
                        StartCoroutine(LoadExtra());

                    }
                )
            );
            GameObject buffParent00 = AssetLoad.ResourceManager.Instance.GetResource(@"UIcomponent/BuffTransform") as GameObject;
            var buffParent0 = GameObject.Instantiate(buffParent00) as GameObject;
            buffParent0.name = "[" + uniqueId + "]buff";
            buffParent0.transform.SetParent(BattleManager.Instance.battlePanel.buffAnchor);
            buffTransform0 = buffParent0.GetComponent<BuffTransform0>();
            buffTransform0.Init(this);

            //var b = System.DateTime.Now;

            //Debug.Log("[DEBUG] current hero:" + heroName);

            if (firstSkill != null)
            {
                StartCoroutine(firstSkill.LoadResource());
            }
            //b = System.DateTime.Now;
            if (secondSkill != null)
            {
                StartCoroutine(secondSkill.LoadResource());
            }
            //b = System.DateTime.Now;
            if (ultimateSkill != null)
            {
                StartCoroutine(ultimateSkill.LoadResource());
            }


            if (!string.IsNullOrEmpty(iconName))
            {
                StartCoroutine(ResourceLoader.GetInstance().textureLoader.LoadTexture("HeroHeader/" + iconName, null));
            }

            StartCoroutine(LoadWinAudio(th));

            CreateBloodBar();


            transform.SetParent(BattleManager.Instance.transform);
            transform.localPosition = new Vector3(10000, 10000, 10000);
            transform.localScale = Vector3.one;
            transform.localEulerAngles = Vector3.zero;

            //添加武器


            //yield return 0;
            //isLoadComplete = true;
            SwitchState(ActorState.None);
        }

        //IEnumerator _LoadResourceAsync()
        //{
           
        //}
        IEnumerator LoadWeapon()
        {
            yield return StartCoroutine(
               model.GetComponent<ModelRenderKit>().LoadWeapons(heroId, weaponId));
            CommonMethod.ChangeLayer(model.transform, "SceneActor");
            model.GetComponent<ModelRenderKit>().SetWeaponEffectLayer("SceneParticle");
            loadedWeapon = true;
        }

        IEnumerator LoadExtra()
        {
            var th = Dict.DictDataManager.Instance.tableHeroDao.GetById(heroId);
            if (th.heroClass == 0 || th.heroClass == 100 || th.heroClass == 101)
            {
                yield return StartCoroutine(
                ResourceLoader.GetInstance().modelLoader.LoadModelExtend(resourceName + ConstData.extendResPostfix,
                    (asset) =>
                    {
                        if(asset != null)
                        {
                            ultimateFull = true;
                            model.GetComponent<ModelRenderKit>().AddBattleAni(asset as AnimClipsAsset);
                        }
                        loadedExtra = true;
                    }
                    )
                );
            }
            else
            {
                loadedExtra = true;
                ultimateFull = true;
            }
        }

        List<string> winAudioNames = new List<string>();

        IEnumerator LoadWinAudio(Dict.DataModel.TableHero dh)
        {
            int taskCount = 0;
            winAudioNames = new List<string>();
            if (!string.IsNullOrEmpty(dh.WinVoiceAudio))
            {
                foreach (var audioName in dh.WinVoiceAudio.Split(','))
                {
                    if (!string.IsNullOrEmpty(audioName))
                    {
                        StartCoroutine(
                        AudioManager.Instance.LoadAudioResource(audioName, () => { taskCount--; }));
                        taskCount++;
                        winAudioNames.Add(audioName);
                    }
                }
            }
            while(taskCount > 0)
            {
                yield return 0;
            }
            loadedWinAudio = true;
        }

        void UnloadWinAudio()
        {
            foreach (var audio in winAudioNames)
            {
                AudioManager.Instance.UnloadAudioResource(audio);
            }
            if (winAudioSource != null)
            {
                winAudioSource.Stop();
            }
        }

        public void UnloadResource()
        {
            var th = Dict.DictDataManager.Instance.tableHeroDao.GetById(heroId);
            if (th.heroClass == 0 || th.heroClass == 100 || th.heroClass == 101)
            {
                if(ultimateFull)
                {
                    model.GetComponent<ModelRenderKit>().RemoveBattleAni();
                }
                ResourceLoader.GetInstance().modelLoader.UnloadModelExtend(resourceName + ConstData.extendResPostfix);
            }
            model.GetComponent<ModelRenderKit>().UnloadWeapons();
            model.GetComponent<ModelRenderKit>().LeaveBattle();
            ResourceLoader.GetInstance().modelLoader.UnloadModel(model, resourceName);
            BattleFactory.UnSpawn(hpBar.gameObject);
            hpBar = null;
            if (!string.IsNullOrEmpty(iconName))
            {
                ResourceLoader.GetInstance().textureLoader.UnloadTexture("HeroHeader/" + iconName);
            }
            if (firstSkill != null)
            {
                firstSkill.UnloadResource();
            }
            if (secondSkill != null)
            {
                secondSkill.UnloadResource();
            }
            if (ultimateSkill != null)
            {
                ultimateSkill.UnloadResource();
            }
            UnloadWinAudio();

            foreach (var obj in particleObjCache)
            {
                if (obj != null)
                {
                    obj.Recycle();
                }
            }
            particleObjCache.Clear();
        }

        bool IsSkillLoadComplete()
        {
            if (firstSkill != null)
            {
                if (!firstSkill.LoadComplete())
                {
                    return false;
                }
            }
            if (secondSkill != null)
            {
                if (!secondSkill.LoadComplete())
                {
                    return false;
                }
            }
            if (ultimateSkill != null)
            {
                if (!ultimateSkill.LoadComplete())
                {
                    return false;
                }
            }
            return true;
        }
        #endregion


        #region Play Particle
        public void PlayHitParticle(BattleSkillRelease release)
        {

            bool isBuffHitParticleOn = false;
            foreach (var buff in ownBuffs)
            {
                bool isPlay;
                buff.OnHit(out isPlay);
                if (isPlay)
                {
                    isBuffHitParticleOn = true;
                }
            }

            if (isBuffHitParticleOn)
            {
                return;
            }
            if (release.beHitParticle_Target != null)
            {
                PlayParticle(release.beHitParticle_Target, true);
            }

            if (release.beHitparticle_Owner != null)
            {
                release.ownBC.PlayParticle(release.beHitparticle_Owner, true);
            }
            if (release.beHitParticle_Ground != null)
            {
                BattleViewCtrl.GetInstance().PlayParticle(release.beHitParticle_Ground, transform.localPosition, true);
            }
        }

        List<ParticleObj> particleObjCache = new List<ParticleObj>();
        public ParticleObj PlayParticle(ParticleData pd, bool isAutoRecovery)
        {
            if (pd.pt == ParticleType.BIND_BONE)
            {
                var trans = GetBindTransform(pd.bindBone);
                if (trans == null)
                {
                    trans = transform;
                }
                var obj = ParticleFactory.CreateParticleObj(pd);
                if (pd.particleId == "336")
                {
                    obj.Play(LayerName.SceneParticle, transform, new Vector3(width / 2f, height / 2f, length / 2f), 1f, Vector3.zero, isAutoRecovery);
                }
                else
                {
                    obj.Play(LayerName.SceneParticle, trans, Vector3.zero, 1f, Vector3.zero, isAutoRecovery);
                }
                particleObjCache.Add(obj);
                return obj;
            }
            else if (pd.pt == ParticleType.BASE_OFFSET)
            {
                var trans = transform;
                var obj = ParticleFactory.CreateParticleObj(pd);
                obj.Play(LayerName.SceneParticle, trans, pd.offset, 1f, Vector3.zero, isAutoRecovery);
                particleObjCache.Add(obj);
                return obj;
            }
            else if (pd.pt == ParticleType.BIND_UI)
            {
                var trans = BattleManager.Instance.battlePanel.GetBCUIParticleTransform(this, pd.bindBone);
                var obj = ParticleFactory.CreateParticleObj(pd);
                trans.PlayParticle(obj, isAutoRecovery);
                return obj;
            }
            else    // NORMAL
            {
                var obj = ParticleFactory.CreateParticleObj(pd);
                obj.Play(LayerName.SceneParticle, transform, Vector3.zero, 1f, Vector3.zero, isAutoRecovery);
                particleObjCache.Add(obj);
                return obj;
            }
        }


        Transform FindBindTransform(Transform trans, string bindName)
        {
            if (trans.name == bindName)
            {
                return trans;
            }
            foreach (Transform t in trans)
            {
                var _t = FindBindTransform(t, bindName);
                if (_t != null)
                {
                    return _t;
                }
            }
            return null;
        }

        public Transform GetBindTransform(string bindName)
        {
            if (model != null && model.GetComponent<ModelRenderKit>() != null)
            {
                return model.GetComponent<ModelRenderKit>().GetBindTransform(bindName);
            }
            return null;
        }

        #endregion

        #region BehaviourPackage
        OnceBehaviourPackage currentPackage;
        Queue<OnceBehaviourPackage> packageQueue = new Queue<OnceBehaviourPackage>();
        List<OnceBehaviourPackage> donePackages = new List<OnceBehaviourPackage>();

        public OnceBehaviourPackage GetCurrentPackage()
        {
            return currentPackage;
        }

        public void AddPackage(OnceBehaviourPackage package)
        {
            packageQueue.Enqueue(package);
            BattleViewCtrl.GetInstance().DoBehaviourPackage(package);
        }
        public bool IsHavePackageNeedDo()
        {
            return packageQueue.Count > 0;
        }
        public OnceBehaviourPackage DequeuePackage()
        {
            if (packageQueue.Count > 0)
                return packageQueue.Dequeue();
            return null;
        }
        public void DoPackage(OnceBehaviourPackage package)
        {
            currentPackage = package;
            if (package.isNeedMove)
            {
                SwitchState(ActorState.AttackMoveForward);
            }
            else
            {
                SwitchState(ActorState.Attack);
            }

            var skill = GetSkill(currentPackage.skillType);

            if (skill != null)
            {
                if (skill.attackCameraRule == AttackCameraRule.Melee)
                    CameraController.Instance.Attack(true, camp, package.FPId);
                else
                    CameraController.Instance.Attack(false, camp, package.FPId);
            }
        }
        public void DonePackage()
        {
            var skill = GetSkill(currentPackage.skillType);
            skill.Done();
            donePackages.Add(currentPackage);
            BattleViewCtrl.GetInstance().DoneBehaviourPackage(currentPackage);
            currentPackage = null;
        }
        #endregion

        public bool IsFirstSkillCanCast4UI()
        {
            return BattleViewCtrl.GetInstance().isSkillCanCast4UI(this, SkillType.Skill1);
        }
        public bool IsSecondSkillCanCast4UI()
        {
            return BattleViewCtrl.GetInstance().isSkillCanCast4UI(this, SkillType.Skill2);
        }
        public bool IsUltimateSkillCanCast4UI()
        {
            return BattleViewCtrl.GetInstance().isSkillCanCast4UI(this, SkillType.Ultimate);
        }

        /// <summary>
        /// 逻辑判断一段技能是否可以释放
        /// </summary>
        /// <returns></returns>
        public bool IsFirstSkillCanCast()
        {
            return IsSkillCanCast(SkillType.Skill1);
        }
        /// <summary>
        /// 逻辑判断二段技能是否可以释放
        /// </summary>
        /// <returns></returns>
        public bool IsSecondSkillCanCast()
        {
            return IsSkillCanCast(SkillType.Skill2);
        }
        /// <summary>
        /// 逻辑判断大招是否可以释放
        /// </summary>
        /// <returns></returns>
        public bool IsUltimateSkillCanCast()
        {
            return IsSkillCanCast(SkillType.Ultimate);
        }

        public void Tick()
        {
            UpdateState();
            if (firstSkill != null)
            {
                firstSkill.Tick();
            }
            if (secondSkill != null)
            {
                secondSkill.Tick();
            }
            if (ultimateSkill != null)
            {
                ultimateSkill.Tick();
            }


            if (particleObjCache.Count > 0)
            {
                for (int i = particleObjCache.Count; i > 0; i--)
                {
                    if (particleObjCache[i-1] == null)
                    {
                        particleObjCache.RemoveAt(i-1);
                    }
                }
            }
        }

        public void ClearParticleRecoveryTask()
        {

        }

        void OnEnable()
        {
            if (buffTransform0 != null)
                buffTransform0.Show();
        }

        void OnDisable()
        {
            if (buffTransform0 != null)
                buffTransform0.Hide();
        }

        public void OnFloatHit()
        {
            var p = Random.Range(0f, 1f);
            if (p <= 0.15f)
            {
                BattleViewCtrl.GetInstance().AddDropWaterBall(this);
            }
        }

        public void HideModel()
        {
            if (model != null)
            {
                model.gameObject.SetActive(false);
            }
            if (hpBar != null)
            {
                hpBar.gameObject.SetActive(false);
            }
        }

        public bool isWillDead = false;


        public void Reborn(double healHP, List<ProtoBuf.Message.ActorSkill> newSkills)
        {
            SetHP(healHP);
            isAlive = true;
            isWillDead = false;
            model.SetActive(false);
            model.SetActive(true);
            PlayStand();
            foreach (var skill in newSkills)
            {
                var s = GetSkill((SkillType)skill.skillType);
                if (s != null)
                {
                    s.Refresh(skill);
                }
            }
            if (BattleViewCtrl.GetInstance().curRunningCamp == camp)
            {
                SwitchState(ActorState.AttackReady);
                BattleManager.Instance.battlePanel.EnterOurTurn();
            }
            else
            {
                SwitchState(ActorState.Defend);
                BattleManager.Instance.battlePanel.LeaveOutTurn();
            }
        }

        public void OnEnterUltimate()
        {
            foreach (var buff in ownBuffs)
            {
                buff.OnEnterUltimate();
            }
            buffTransform0.Hide();

        }
        public void OnLeaveUltimate()
        {
            foreach (var buff in ownBuffs)
            {
                buff.OnLeaveUltimate();
            }
            buffTransform0.Show();

        }

        public void PlayWinAudio()
        {
            if (winAudioNames.Count > 0)
            {
                int index = Random.Range(0, winAudioNames.Count);
                winAudioSource = AudioManager.Instance.PlaySingle(winAudioNames[index]);
                Debug.Log("[PlayWinAudio] PlayWinAudio:" + winAudioNames[index]);
            }
        }
        private bool ultimateFull = false;
        public bool UltimateFull()
        {
            if(!ultimateFull || ultimateSkill == null)
            {
                return false;
            }
            return anim.anim.GetClip(ultimateSkill.animName) != null;
            
        }
        AudioSource winAudioSource;
    }

}